<?php


namespace App\Common\Libs;


use App\Consts\ExceptionCode;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;

class YAPI
{
    // 是否完成
    public const STATUS_TODO = 'undone';
    public const STATUS_FINISHED = 'done';
    public static $status = [
        0 => self::STATUS_TODO,
        1 => self::STATUS_FINISHED
    ];

    // 请求参数类型
    public const REQ_BODY_TYPE_FORM = 'form';
    public const REQ_BODY_TYPE_JSON = 'json';
    public const REQ_BODY_TYPE_FILE = 'file';
    public const REQ_BODY_TYPE_RAW = 'raw';

    // 返回数据类型
    public const RES_BODY_TYPE_JSON = 'json';
    public const RES_BODY_TYPE_RAW = 'raw';

    // 接口是否公开
    public const API_CLOSE = false;
    public const API_OPEN = true;

    private static $_yapi;

    // Yapi接口基础地址
    private $baseUrl = 'http://116.62.240.38:3000/api';

    // Yapi超级管理员账号
    private $adminAccount;

    // Yapi超级管理员密码
    private $adminPassword;

    // 包含_yapi_token和_yapi_uid，二者必须登陆后从cookie中获得
    private $cookies;

    public function __construct($adminAccount, $adminPassword)
    {
        $this->adminAccount = $adminAccount;
        $this->adminPassword = $adminPassword;

        $cookies = $this->login();

        $this->cookies = CookieJar::fromArray($cookies, '116.62.240.38');
    }

    /**
     * 入口
     * @return YAPI
     */
    public static function getInstance($adminAccount, $adminPassword)
    {
        if (self::$_yapi === null) {
            self::$_yapi = new self($adminAccount, $adminPassword);
        }
        return self::$_yapi;
    }

    private function login()
    {
        $url = $this->baseUrl . '/user/login';
        $loginData = [
            'email' => $this->adminAccount,
            'password' => $this->adminPassword,
        ];
        $response = $this->sendClient($url, $loginData, 'POST', null, 'getCookies');
        $cookies = [];
        foreach ($response->getHeaders()['Set-Cookie'] as $cookieStr) {
            $cookieInfo = explode(';', $cookieStr);
            foreach ($cookieInfo as $value) {
                $cookieData = explode('=', $value);
                $cookies[$cookieData[0]] = $cookieData[1] ?? $cookieData[0];
            }
        }

        return $cookies;
    }

    public function addCategory($params)
    {
        if (empty($params['project_id'])) {
            return false;
        }

        $params = ArrayHelper::merge($params, [
            'desc' => $params['description'] ?? '',
        ]);
        $url = $this->baseUrl . '/interface/add_cat';
        $response = $this->sendClient($url, $params, 'POST', $this->cookies);
        $result = $this->getContents($response);
        if ((int)$result['errcode'] != 0) {
            return false;
        }

        return $result['data'];
    }

    /**
     * 获取所有空间
     * @return array
     * @throws \yii\base\InvalidConfigException
     */
    public function getGroup()
    {
        $url = $this->baseUrl . '/group/list';
        $response = $this->sendClient($url, [], 'GET', $this->cookies);
        $groups = $this->getContents($response);
        $result = [];
        foreach ($groups['data'] as $projectInfo) {
            $result[$projectInfo['group_name']] = $projectInfo['_id'];
        }
        return $result;
    }

    /**
     * 获取某空间下的所有项目
     * @param $groupName [空间名称】
     * @param int $page [页数，默认是1]
     * @param int $limit [取出的数量，默认是10]
     * @return array
     * @throws \yii\base\InvalidConfigException
     */
    public function getAllProject($groupName, $page = 1, $limit = 10)
    {
        $groups = $this->getGroup();
        if (empty($groups[$groupName])) {
            abort(ExceptionCode::CODE_FAIL, '空间不存在');
        }
        $groupId = $groups[$groupName];
        $url = $this->baseUrl . '/project/list?group_id=' . $groupId . '&page=' . $page . '&limit=' . $limit;
        $response = $this->sendClient($url, [], 'GET', $this->cookies);
        $projects = $this->getContents($response);
        $result = [];
        foreach ($projects['data']['list'] as $projectInfo) {
            $result[$projectInfo['name']] = $projectInfo['_id'];
        }
        return $result;
    }

    /**
     * 获取某空间下某个项目
     * @param $groupName
     * @param $projectName
     * @param int $page
     * @param int $limit
     * @return array|\Illuminate\Http\JsonResponse
     */
    public function getOneProject($groupName, $projectName, $page = 1, $limit = 10)
    {
        $result = [];

        $projects = $this->getAllProject($groupName, $page, $limit);
        if (empty($projects[$projectName])) {
            abort(ExceptionCode::CODE_FAIL, '项目不存在');
        }

        $result[$projectName] = $projects[$projectName];

        return $result;
    }

    /**
     * 获取导航
     * @param $groupName
     * @param $projectName
     * @return array|\Illuminate\Http\JsonResponse
     */
    public function getCategoryMenu($groupName, $projectName)
    {
        $projects = $this->getAllProject($groupName);
        if (empty($projects[$projectName])) {
            abort(ExceptionCode::CODE_FAIL, '项目不存在');
        }
        $projectId = $projects[$projectName];

        $url = $this->baseUrl . '/interface/getCatMenu?project_id=' . $projectId;
        $response = $this->sendClient($url, [], 'GET', $this->cookies);
        $categoryMenus = $this->getContents($response);

        $result = [];
        foreach ($categoryMenus['data'] as $categoryMenuInfo) {
            $result[$categoryMenuInfo['name']] = $categoryMenuInfo['_id'];
        }
        return $result;
    }

    /**
     * 保存接口
     * @param $data
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function saveDoc($data)
    {
        $url = $this->baseUrl . '/interface/save';
        return $this->sendClient($url, $data, 'POST', $this->cookies);
    }

    /**
     * 获取结果返回
     * @param $response
     * @return \Illuminate\Http\JsonResponse|mixed|null
     */
    public function getContents($response)
    {
        return Json::decode($response->getBody()->getContents());
    }

    /**
     * 发送请求
     * @param $url
     * @param null $options
     * @param string $method
     * @param null $cookies
     * @param string $result
     * @return \Psr\Http\Message\ResponseInterface
     */
    private function sendClient($url, $options = null, $method = 'GET', $cookies = null, $result = 'data')
    {
        $client = new Client();
        return $client->request($method, $url, [
            'json' => $options,
            'cookies' => $cookies
        ]);
    }
}
